package api

import (
	"context"
	"net/http"
	"strconv"
	"strings"
	"trade_api/global"
	"trade_api/models/request"
	"trade_api/models/response"

	pb "trade_api/proto"

	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
)

// PostCreateTradeProver 新建 trade prover
func PostCreateTradeProver(c *gin.Context) {

	// 表单验证
	var req request.CreateTradeProverReq
	if err := c.ShouldBindJSON(&req); err != nil {
		HandleValidatorError(c, err)
		return
	}

	// 验证参数

	portalIds := strings.Split(req.RecordIDs, ",")
	portalProvinceCodes := strings.Split(req.RecordProvinceCodes, ",")
	prices := strings.Split(req.Prices, ",")
	portalRecordCount := len(portalIds)

	if portalRecordCount != len(portalProvinceCodes) {
		zap.L().Error("portalids 和 provinceIds 长度不同",
			zap.String("trade_id",
				req.TradeID),
			zap.String("record_ids", req.RecordIDs),
			zap.String("record_province_codes", req.RecordProvinceCodes),
		)
		c.JSON(http.StatusOK, response.Response{

			Code:    http.StatusBadRequest,
			Message: "portalids 和 provinceIds 长度不同, 存证数据有误",
		})
		return
	}
	if len(prices) != portalRecordCount-1 {
		zap.L().Error("prices 应该为 portalids长度减1",
			zap.String("trade_id",
				req.TradeID),
			zap.String("trade_sn", req.TradeSn),
		)
		c.JSON(http.StatusOK, response.Response{

			Code:    http.StatusBadRequest,
			Message: "prices 应该为 portalids长度减1, 存证数据有误",
		})
		return
	}

	// TODO: 根据province code 的最后一个位置，确定存在哪个区域链中
	provinceCode := portalProvinceCodes[len(portalProvinceCodes)-1]

	// 通过srv服务 创建 trade record
	resp, err := global.TradeRpcClient.CreateTradeRecord(context.Background(), &pb.CreateTradeRecordRequest{
		TradeId:             req.TradeID,
		TradeSn:             req.TradeSn,
		UserId:              req.UserID,
		SnapTime:            req.SnapTime,
		LicensePlateNumber:  req.LicensePlateNumber,
		LicensePlateNumber2: req.LicensePlateNumber2,
		RecordIds:           req.RecordIDs,
		RecordProvinceCodes: req.RecordProvinceCodes,
		Prices:              req.Prices,
		TotalPrice:          req.TotalPrice,
		ProvinceCode:        provinceCode,
	})

	if err != nil {
		zap.L().Error("trade 服务调用失败",
			zap.Error(err),
			zap.String("trade_id",
				req.TradeID),
			zap.String("trade_sn", req.TradeSn),
			zap.String("user_id", req.UserID),
			zap.String("snap_time", req.SnapTime),
		)
		c.JSON(http.StatusOK, response.Response{

			Code:    http.StatusBadRequest,
			Message: "trade服务调用失败",
		})
		return
	}

	// 将创建成功的tx的哈希发送到对应的mq中，用来检查交易的状态。
	go func() {
		defer func() {
			if err := recover(); err != nil {
				zap.L().Error("运行时错误", zap.Any("err", err))
			}
		}()
		err := global.Producer.Publish(resp.TxHash)
		if err != nil {
			// 记录错误日志
			zap.L().Error("发布mq消息失败",
				zap.Error(err),
				zap.String("tx.Hash",
					resp.TxHash),
			)
		}
	}()

	c.JSON(http.StatusOK, response.Response{
		Code:    http.StatusOK,
		Message: "success",
		Data: response.CreatePortalProverResponse{
			ID:       int(resp.Id),
			HashText: resp.HashText,
			TxHash:   resp.TxHash,
		},
	})
}

// GetTradeRecord 根据tx hash 获取 trade record
func GetTradeRecord(c *gin.Context) {
	// 表单验证
	var req request.GetTradeRecordReq
	if err := c.ShouldBindUri(&req); err != nil {
		HandleValidatorError(c, err)
		return
	}

	params := strings.Split(req.Hash, ":")
	if len(params) != 3 {
		zap.L().Error("哈希参数错误",
			zap.String("portal record hash",
				req.Hash),
		)
		c.JSON(http.StatusOK, response.Response{
			Code:    http.StatusBadRequest,
			Message: "哈希参数错误",
		})
		return
	}

	// ProvinceCode:TradeID:HashText
	// provinceCode := params[0]
	// tradeId := params[1]

	// TODO: 缓存优化问题
	// TODO: 根据province code 确定从哪个区域链中获取信息

	// 获取 trade record 信息
	tradeResp, err := global.TradeRpcClient.GetTradeRecord(context.Background(), &pb.GetTradeRecordRequest{
		HashText: req.Hash,
	})
	if err != nil {
		zap.L().Error("trade 服务调用失败",
			zap.Error(err),
			zap.String("trade_hash",
				req.Hash),
		)
		c.JSON(http.StatusOK, response.Response{

			Code:    http.StatusBadRequest,
			Message: "trade服务调用失败",
		})
		return
	}

	// 获取 portal record 信息
	portalIds := strings.Split(tradeResp.RecordIds, ",")
	portalProvinceCodes := strings.Split(tradeResp.RecordProvinceCodes, ",")
	prices := strings.Split(tradeResp.Prices, ",")
	portalRecordCount := len(portalIds)

	if portalRecordCount != len(portalProvinceCodes) {
		zap.L().Error("portalids 和 provinceIds 长度不同",
			zap.String("trade_hash",
				req.Hash),
			zap.String("record_ids", tradeResp.RecordIds),
			zap.String("record_province_codes", tradeResp.RecordProvinceCodes),
		)
		c.JSON(http.StatusOK, response.Response{

			Code:    http.StatusBadRequest,
			Message: "portalids 和 provinceIds 长度不同, 存证数据有误",
		})
		return
	}

	if len(prices) != portalRecordCount-1 {
		zap.L().Error("prices 应该为 portalids长度减1",
			zap.String("trade_hash",
				req.Hash),
			zap.String("record_ids", tradeResp.RecordIds),
			zap.String("record_province_codes", tradeResp.RecordProvinceCodes),
		)
		c.JSON(http.StatusOK, response.Response{
			Code:    http.StatusBadRequest,
			Message: "prices 应该为 portalids长度减1, 存证数据有误",
		})
		return
	}

	// portal records
	portalRecords := make([]response.PortalRecord, 0, portalRecordCount)

	for i := 0; i < portalRecordCount; i++ {
		portalId := portalIds[i] // portal 的 record id
		provinceCode := portalProvinceCodes[i]

		// 获取 portal record
		portalResp, err := global.PortalRpcClient.GetPortalRecord(context.Background(), &pb.GetPortalRecordRequest{
			RecordId:     portalId,
			ProvinceCode: provinceCode,
		})

		if err != nil {
			zap.L().Error("portal 服务调用失败",
				zap.Error(err),
				zap.String("portal_record_id",
					portalId),
				zap.String("province_code", provinceCode),
			)
			c.JSON(http.StatusOK, response.Response{

				Code:    http.StatusBadRequest,
				Message: "portal 服务调用失败",
			})
			return
		}

		record := response.PortalRecord{
			PortalCode:               portalResp.PortalCode,
			SnapTime:                 portalResp.SnapTime,
			LicensePlateNumber:       portalResp.LicensePlateNumber,
			LicensePlateNumber2:      portalResp.LicensePlateNumber2,
			LicensePlateColor:        portalResp.LicensePlateColor,
			LicensePlateColor2:       portalResp.LicensePlateColor2,
			VehicleColor:             portalResp.VehicleColor,
			VehicleModel:             portalResp.GetVehicleModel(),
			LaneNumber:               portalResp.LaneNumber,
			SnapNumber:               portalResp.SnapNumber,
			DangerousChemicalsSymols: portalResp.DangerousChemicalsSymols,
			DangerousChemicalsType:   portalResp.DangerousChemicalsType,
			AxleType:                 portalResp.AxleType,
			AxleNumber:               portalResp.AxleNumber,
			WheelNumber:              portalResp.WheelNumber,
			VehicleSpeed:             portalResp.VehicleSpeed,
			VehicleLength:            portalResp.VehicleLength,
			TrafficVehicleModel:      portalResp.TrafficVehicleModel,
			ImgExist:                 portalResp.ImgExist,
			BeforeCompress:           portalResp.BeforeCompress,
			AfterCompress:            portalResp.AfterCompress,
			VehicleWidth:             portalResp.VehicleWidth,
			VehicleHeight:            portalResp.VehicleHeight,
			ImageType:                portalResp.ImageType,
			ImageUrl:                 portalResp.ImageUrl,
			RecordId:                 portalResp.RecordId,
			BlockChainHashCode:       portalResp.BlockChainHashCode,
			RecordHashCode:           portalResp.RecordHashCode,
			ProvinceCode:             provinceCode,
			BelongVideoUrl:           portalResp.BelongVideoUrl,
			BelongVideoStartTime:     portalResp.BelongVideoStartTime,
			BelongVideoEndTime:       portalResp.BelongVideoEndTime,
			Status:                   int(portalResp.Status),
			Price:                    0,
		}
		if i > 0 {
			record.Price, err = strconv.Atoi(prices[i-1])
			if err != nil {
				zap.L().Error("parse price failed",
					zap.Error(err),
					zap.String("portal_record_id",
						portalId),
					zap.String("province_code", provinceCode),
				)
			}
		}

		portalRecords = append(portalRecords, record)
	}

	c.JSON(http.StatusOK, response.Response{
		Code:    http.StatusOK,
		Message: "success",
		Data: response.GetTradeRecordRsponse{
			TradeID:             tradeResp.TradeId,
			TradeSn:             tradeResp.TradeSn,
			UserID:              tradeResp.UserId,
			SnapTime:            tradeResp.SnapTime,
			LicensePlateNumber:  tradeResp.LicensePlateNumber,
			LicensePlateNumber2: tradeResp.LicensePlateNumber2,
			RecordIDs:           tradeResp.RecordIds,
			RecordProvinceCodes: tradeResp.RecordProvinceCodes,
			Prices:              tradeResp.Prices,
			TotalPrice:          tradeResp.TotalPrice,
			PortalRecords:       portalRecords,
		},
	})

}
